#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <errno.h>

#ifdef IPP
#include <ipp.h>
#include <ippdefs.h>
#endif

typedef double FLOAT;
typedef unsigned int UINT32;
typedef unsigned long long int UINT64;
typedef unsigned char UINT8;

// PPM Edge Enhancement Code
//
UINT8 header[22];
UINT8 R[92600];
UINT8 G[921600];
UINT8 B[921600];
UINT8 convR[921600];
UINT8 convG[921600];
UINT8 convB[921600];
UINT8 R1[921600];
UINT8 G1[921600];
UINT8 B1[921600];

UINT8 red1 [3] ={66, 0, 0} ;
UINT8 redor1 [3]= {'FF', 33, 0};
UINT8 orange1[3]={'FF',99,0};
UINT8 orangeyel1[3]={'FF','CC',0};
UINT8 yellow1[3]= {'FF','FF',0};
UINT8 yellowgr1[3]={'FF','CC',99};
UINT8 blue1[3]= {33,99,'FF'};
UINT8 bluegr1[3]={99,'FF','CC'};
UINT8 green1[3]={66,'CC',99};
UINT8 bluevi1[3]={33,33,'FF'};
UINT8 violet1[3]={66,0,'FF'};
UINT8 violetre1[3]={'FF',33,'FF'};
UINT8 white1[3]={'FF','FF','FF'};
UINT8 black1[3]={0,0,0};
UINT8 brown1[3]={99,33,0};


FLOAT red [3] ={102.0, 0.0, 0.0} ;
FLOAT redor [3]= {255.0, 51.0, 0.0};
FLOAT orange[3]={255.0,153.0,0.0};
FLOAT orangeyel[3]={255.0,204.0,0.0};
FLOAT yellow[3]= {255.0,255.0,0.0};
FLOAT yellowgr[3]={255.0,204.0,153.0};
FLOAT blue[3]= {51.0,153.0,255.0};
FLOAT bluegr[3]={153.0,255.0,204.0};
FLOAT green[3]={102.0,204.0,153.0};
FLOAT bluevi[3]={51.0,51.0,255.0};
FLOAT violet[3]={102.0,0.0,255.0};
FLOAT violetre[3]={255.0,51.0,255.0};
FLOAT white[3]={255.0,255.0,255.0};
FLOAT black[3]={0.0,0.0,0.0};
FLOAT brown[3]={153.0,51.0,0.0};
FLOAT yellowgre[3]={255.0,255.0,204.0};
FLOAT greenbl[3]={153.0,255.0,255.0};
FLOAT pink[3]={255.0,153.0,255.0};
FLOAT offbl[3]={0.0,153.0,204.0};
FLOAT greenyel[3]={204.0,255.0,102.0};
FLOAT greywh[3]={204.0,204.0,204.0};
FLOAT greybl[3]={51.0,51.0,51.0};

FLOAT re,reor,or,orye,ye,yegr,bl,blgr,gr,blvi,vi,vire,wh,bla,br,yegr,grbl,pi,ofbl,grbl,grwh,grbla,gryl;
FLOAT a,b,c,d,e,f,g,h,k,l,m,n,o,p,q,r,s,t,u,v,w,x;
#define K 4.0

FLOAT PSF[9] = {-K/8.0, -K/8.0, -K/8.0, -K/8.0, K+1.0, -K/8.0, -K/8.0, -K/8.0, -K/8.0};


/*................................Sharppen ........................................................*/

void sharprof ()
{
int i,j;
FLOAT temp;
printf("In sharpen");
   // Skip first and last row, no neighbors to convolve with
    for( i=1; i<299; i++)
    {

        // Skip first and last column, no neighbors to convolve with
        for( j=1; j<168; j++)
        {
            temp=0;
            temp += (PSF[0] * (FLOAT)R1[((i-1)*1280)+j-1]);
            temp += (PSF[1] * (FLOAT)R1[((i-1)*1280)+j]);
            temp += (PSF[2] * (FLOAT)R1[((i-1)*1280)+j+1]);
            temp += (PSF[3] * (FLOAT)R1[((i)*1280)+j-1]);
            temp += (PSF[4] * (FLOAT)R1[((i)*1280)+j]);
            temp += (PSF[5] * (FLOAT)R1[((i)*1280)+j+1]);
            temp += (PSF[6] * (FLOAT)R1[((i+1)*1280)+j-1]);
            temp += (PSF[7] * (FLOAT)R1[((i+1)*1280)+j]);
            temp += (PSF[8] * (FLOAT)R1[((i+1)*1280)+j+1]);
	    if(temp<0.0) temp=0.0;
	    if(temp>255.0) temp=255.0;
	    convR[(i*1280)+j]=(UINT8)temp;

            temp=0;
            temp += (PSF[0] * (FLOAT)G1[((i-1)*1280)+j-1]);
            temp += (PSF[1] * (FLOAT)G1[((i-1)*1280)+j]);
            temp += (PSF[2] * (FLOAT)G1[((i-1)*1280)+j+1]);
            temp += (PSF[3] * (FLOAT)G1[((i)*1280)+j-1]);
            temp += (PSF[4] * (FLOAT)G1[((i)*1280)+j]);
            temp += (PSF[5] * (FLOAT)G1[((i)*1280)+j+1]);
            temp += (PSF[6] * (FLOAT)G1[((i+1)*1280)+j-1]);
            temp += (PSF[7] * (FLOAT)G1[((i+1)*1280)+j]);
            temp += (PSF[8] * (FLOAT)G1[((i+1)*1280)+j+1]);
	    if(temp<0.0) temp=0.0;
	    if(temp>255.0) temp=255.0;
	    convG[(i*1280)+j]=(UINT8)temp;

            temp=0;
            temp += (PSF[0] * (FLOAT)B1[((i-1)*1280)+j-1]);
            temp += (PSF[1] * (FLOAT)B1[((i-1)*1280)+j]);
            temp += (PSF[2] * (FLOAT)B1[((i-1)*1280)+j+1]);
            temp += (PSF[3] * (FLOAT)B1[((i)*1280)+j-1]);
            temp += (PSF[4] * (FLOAT)B1[((i)*1280)+j]);
            temp += (PSF[5] * (FLOAT)B1[((i)*1280)+j+1]);
            temp += (PSF[6] * (FLOAT)B1[((i+1)*1280)+j-1]);
            temp += (PSF[7] * (FLOAT)B1[((i+1)*1280)+j]);
            temp += (PSF[8] * (FLOAT)B1[((i+1)*1280)+j+1]);
	    if(temp<0.0) temp=0.0;
	    if(temp>255.0) temp=255.0;
	    convB[(i*1280)+j]=(UINT8)temp;
        }
    }
printf("sharpen done");
}

/*.......................................................................The Quantization function........................................................*/
void colorquant()
{
int i,j;
FLOAT temp;
   // Skip first and last row, no neighbors to convolve with
   //for( i=1; i<300; i++)
    //{

        // Skip first and last column, no neighbors to convolve with
        for( j=1; j<50400; j++)
        {
/*.....................................................Find Eulidean distances from each pallette color................................................*/
		
		a=pow(((FLOAT)R[j]-red[0]),2.0)+pow(((FLOAT)G[j]-red[1]),2.0)+pow(((FLOAT)B[j]-red[2]),2.0);
		re=sqrt(a);
		//printf("%f\n",re);
		b=pow(((FLOAT)R[j]-redor[0]),2.0)+pow(((FLOAT)G[j]-redor[1]),2.0)+pow(((FLOAT)B[j]-redor[2]),2.0);
		reor=sqrt(b);
				//printf("%f\n",reor);
		c=pow(((FLOAT)R[j]-orange[0]),2.0)+pow(((FLOAT)G[j]-orange[1]),2.0)+pow(((FLOAT)B[j]-orange[2]),2.0);
		or=sqrt(c);
				//printf("%f\n",or);
		d=pow(((FLOAT)R[j]-orangeyel[0]),2.0)+pow(((FLOAT)G[j]-orangeyel[1]),2.0)+pow(((FLOAT)B[j]-orangeyel[2]),2.0);
		orye=sqrt(d);
				//printf("%f\n",orye);
		e =pow(((FLOAT)R[j]-yellow[0]),2.0)+pow(((FLOAT)G[j]-yellow[1]),2.0)+pow(((FLOAT)B[j]-yellow[2]),2.0);
		ye=sqrt(e);
				//printf("%f\n",ye);
		f =pow(((FLOAT)R[j]-yellowgr[0]),2.0)+pow(((FLOAT)G[j]-yellowgr[1]),2.0)+pow(((FLOAT)B[j]-yellowgr[2]),2.0);
		yegr=sqrt(f);
				//printf("%f\n",yegr);
		g =pow(((FLOAT)R[j]-blue[0]),2.0)+pow(((FLOAT)G[j]-blue[1]),2.0)+pow(((FLOAT)B[j]-blue[2]),2.0);
		bl=sqrt(g);
				//printf("%f\n",bl);
		h =pow(((FLOAT)R[j]-bluegr[0]),2.0)+pow(((FLOAT)G[j]-bluegr[1]),2.0)+pow(((FLOAT)B[j]-bluegr[2]),2.0);
		blgr=sqrt(h);
				//printf("%f\n",blgr);
		k =pow(((FLOAT)R[j]-violet[0]),2.0)+pow(((FLOAT)G[j]-violet[1]),2.0)+pow(((FLOAT)B[j]-violet[2]),2.0);
		vi=sqrt(k);
				//printf("%f\n",vi);
		l =pow(((FLOAT)R[j]-bluevi[0]),2.0)+pow(((FLOAT)G[j]-bluevi[1]),2.0)+pow(((FLOAT)B[j]-bluevi[2]),2.0);
		blvi=sqrt(l);
				//printf("%f\n",blvi);
		m =pow(((FLOAT)R[j]-green[0]),2.0)+pow(((FLOAT)G[j]-green[1]),2.0)+pow(((FLOAT)B[j]-green[2]),2.0);
		gr=sqrt(m);
				//printf("%f\n",gr);
		n =pow(((FLOAT)R[j]-violetre[0]),2.0)+pow(((FLOAT)G[j]-violetre[1]),2.0)+pow(((FLOAT)B[j]-violetre[2]),2.0);
		vire=sqrt(n);
				//printf("%f\n",vire);
		o=pow(((FLOAT)R[j]-white[0]),2.0)+pow(((FLOAT)G[j]-white[1]),2.0)+pow(((FLOAT)B[j]-white[2]),2.0);	
		wh=sqrt(o);		
				//printf("%f\n",wh);
		p=pow(((FLOAT)R[j]-black[0]),2.0)+pow(((FLOAT)G[j]-black[1]),2.0)+pow(((FLOAT)B[j]-black[2]),2.0);
		bla=sqrt(p);
				//printf("%f\n",bla);
		q=pow(((FLOAT)R[j]-brown[0]),2.0)+pow(((FLOAT)G[j]-brown[1]),2.0)+pow(((FLOAT)B[j]-brown[2]),2.0);
		br=sqrt(q);
				//printf("%f\n",br);
				
		r=pow(((FLOAT)R[j]-yellowgre[0]),2.0)+pow(((FLOAT)G[j]-yellowgre[1]),2.0)+pow(((FLOAT)B[j]-yellowgre[2]),2.0);
		yegr=sqrt(q);		
		
		s=pow(((FLOAT)R[j]-greenbl[0]),2.0)+pow(((FLOAT)G[j]-greenbl[1]),2.0)+pow(((FLOAT)B[j]-greenbl[2]),2.0);
		grbl=sqrt(q);
		
		t=pow(((FLOAT)R[j]-pink[0]),2.0)+pow(((FLOAT)G[j]-pink[1]),2.0)+pow(((FLOAT)B[j]-pink[2]),2.0);
		pi=sqrt(q);
		
		u=pow(((FLOAT)R[j]-offbl[0]),2.0)+pow(((FLOAT)G[j]-offbl[1]),2.0)+pow(((FLOAT)B[j]-offbl[2]),2.0);
		ofbl=sqrt(q);
		
		v=pow(((FLOAT)R[j]-greenyel[0]),2.0)+pow(((FLOAT)G[j]-greenyel[1]),2.0)+pow(((FLOAT)B[j]-greenyel[2]),2.0);
		gryl=sqrt(q);
		
		w=pow(((FLOAT)R[j]-greywh[0]),2.0)+pow(((FLOAT)G[j]-greywh[1]),2.0)+pow(((FLOAT)B[j]-greywh[2]),2.0);
		grwh=sqrt(q);
		
		x=pow(((FLOAT)R[j]-greybl[0]),2.0)+pow(((FLOAT)G[j]-greybl[1]),2.0)+pow(((FLOAT)B[j]-greybl[2]),2.0);
		grbla=sqrt(q);
		
		

/*..................................................................sort to find the lowest..........................................................*/


            FLOAT mindis;
		mindis = re;
		if (mindis>reor)
		{mindis=reor;}
		if (mindis>or)
		{mindis=or;}
		if (mindis>orye)
		{mindis=orye;}
		if (mindis>ye)
		{mindis=ye;}
		if (mindis>yegr)
		{mindis=yegr;}
		if (mindis>bl)
		{mindis=bl;}
		if (mindis>blgr)
		{mindis=blgr;}
		if (mindis>vi)
		{mindis=vi;}
		if (mindis>blvi)
		{mindis=blvi;}
		if (mindis>gr)
		{mindis=gr;}
		if (mindis>vire)
		{mindis=vire;}
		if (mindis>wh)
		{mindis=wh;}
		if (mindis>bl)
		{mindis=bla;}
		if (mindis>br)
		{mindis=br;}
		if (mindis>yegr)
		{mindis=yegr;}
		if (mindis>grbl)
		{mindis=grbl;}
		if (mindis>pi)
		{mindis=pi;}
		if (mindis>ofbl)
		{mindis=ofbl;}
		if (mindis>gryl)
		{mindis=gryl;}
		if (mindis>grwh)
		{mindis=grwh;}
		if (mindis>grbla)
		{mindis=grbla;}
		//printf("\nquantized color is %f\n",mindis);
/*..........................	....................................depending on the lowest euclidean distance switch color..............................*/
		if (mindis==re)
		{

		R1[j]=(UINT8)red[0];
		G1[j]=(UINT8)red[1];
		B1[j]=(UINT8)red[2];
		}
		else if (mindis==reor)
		{ 
		R1[j]=(UINT8)redor[0];
		G1[j]=(UINT8)redor[1];
		B1[j]=(UINT8)redor[2];
		}
		else if (mindis==or) 
		{
		R1[j]=(UINT8)orange[0];
		G1[j]=(UINT8)orange[1];
		B1[j]=(UINT8)orange[2];
		}
		else if (mindis==orye)
		{
		R1[j]=(UINT8)orangeyel[0];
		G1[j]=(UINT8)orangeyel[1];
		B1[j]=(UINT8)orangeyel[2];
		}
		else if (mindis==ye) 
		{
		R1[j]=(UINT8)yellow[0];
		G1[j]=(UINT8)yellow[1];
		B1[j]=(UINT8)yellow[2];
		}
		else if (mindis==yegr)
		{
		R1[j]=(UINT8)yellowgr[0];
		G1[j]=(UINT8)yellowgr[1];
		B1[j]=(UINT8)yellowgr[2];
		}
		else if (mindis==bl)
		{
		R1[j]=(UINT8)blue[0];
		G1[j]=(UINT8)blue[1];
		B1[j]=(UINT8)blue[2];
		}
		else if (mindis==blgr)
		{
		R1[j]=(UINT8)bluegr[0];
		G1[j]=(UINT8)bluegr[1];
		B1[j]=(UINT8)bluegr[2];
		}
		else if (mindis==vi)
		{
		R1[j]=(UINT8)violet[0];
		G1[j]=(UINT8)violet[1];
		B1[j]=(UINT8)violet[2];
		}
		else if (mindis==blvi)
		{
		R1[j]=(UINT8)bluevi[0];
		G1[j]=(UINT8)bluevi[1];
		B1[j]=(UINT8)bluevi[2];
		}
		else if (mindis==gr) 
		{
		R1[j]=(UINT8)green[0];
		G1[j]=(UINT8)green[1];
		B1[j]=(UINT8)green[2];
		}
		else if (mindis==vire)
		{
		R1[j]=(UINT8)violetre[0];
		G1[j]=(UINT8)violetre[1];
		B1[j]=(UINT8)violetre[2];
		}
		else if (mindis==wh)
		{
		R1[j]=(UINT8)white[0];
		G1[j]=(UINT8)white[1];
		B1[j]=(UINT8)white[2];
		}
		else if (mindis==bla)
		{
		R1[j]=(UINT8)black[0];
		G1[j]=(UINT8)black[1];
		B1[j]=(UINT8)black[2];
		}
		else if (mindis==br) 
		{
		R1[j]=(UINT8)brown[0];
		G1[j]=(UINT8)brown[1];
		B1[j]=(UINT8)brown[2];
		}
		else if (mindis==yegr) 
		{
		R1[j]=(UINT8)yellowgre[0];
		G1[j]=(UINT8)yellowgre[1];
		B1[j]=(UINT8)yellowgre[2];
		}
		else if (mindis==grbl) 
		{
		R1[j]=(UINT8)greenbl[0];
		G1[j]=(UINT8)greenbl[1];
		B1[j]=(UINT8)greenbl[2];
		}
		else if (mindis==pi) 
		{
		R1[j]=(UINT8)pink[0];
		G1[j]=(UINT8)pink[1];
		B1[j]=(UINT8)pink[2];
		}
		else if (mindis==ofbl) 
		{
		R1[j]=(UINT8)offbl[0];
		G1[j]=(UINT8)offbl[1];
		B1[j]=(UINT8)offbl[2];
		}
		else if (mindis==br) 
		{
		R1[j]=(UINT8)brown[0];
		G1[j]=(UINT8)brown[1];
		B1[j]=(UINT8)brown[2];
		}
		else if (mindis==gryl) 
		{
		R1[j]=(UINT8)greenyel[0];
		G1[j]=(UINT8)greenyel[1];
		B1[j]=(UINT8)greenyel[2];
		}
		else if (mindis==grwh) 
		{
		R1[j]=(UINT8)greywh[0];
		G1[j]=(UINT8)greywh[1];
		B1[j]=(UINT8)greywh[2];
		}
		else if (mindis==grbla) 
		{
		R1[j]=(UINT8)greybl[0];
		G1[j]=(UINT8)greybl[1];
		B1[j]=(UINT8)greybl[2];
		}
		
		
		/*if (j==1 || j==23)
	{
	printf("\nmindis %f",mindis);
	printf("\nconvR%i",convR[j]);
	printf("\nconvG%i",convG[j]);
	printf("\nconvB%i",convB[j]);
	}*/
        }
   //}



}


/*.................................................................The Read from File function.....................................................*/

int IOread ()
{
int fdin;
if((fdin = open("sunset.ppm", O_RDONLY, 0644))<0)
printf("error opening file\n");
int bytesRead=0, bytesLeft,i,j;

    bytesLeft=21;

    //printf("Reading header\n");

    do
    {
        //printf("bytesRead=%d, bytesLeft=%d\n", bytesRead, bytesLeft);
        bytesRead=read(fdin, (void *)header, bytesLeft);
        bytesLeft -= bytesRead;
    } while(bytesLeft > 0);

    header[21]='\0';

    //printf("header = %s\n", header);
    // printf("header = %s\n", header[1]);

    // Read RGB data
    //for( i=1; i<300; i++)
    //{
    for(i=0; i<50400; i++)
    {
        read(fdin, (void *)&R[i], 1); convR[i]=R[i];
        read(fdin, (void *)&G[i], 1); convG[i]=G[i];
        read(fdin, (void *)&B[i], 1); convB[i]=B[i];
	/*if (i==1 || i==2)
	{
	printf("\n%x",R[i]);
	printf("\n%x",G[i]);
	printf("\n%x",B[i]);
	}*/
    }
    //}
     
     return fdin;  

}


/*....................................................................The Write to File function.....................................................*/
void IOwrite()

{
int fdout,i,j,k=0,dimx=300,dimy=168,r1,r2,r3;
 //printf("\nhere\n");
 FILE *fp = fopen("sharpen.ppm", "wb");
 FILE *fp2=fopen("result.txt","w");
 printf("file opened\n");
    //write(fdout, (void *)header, 21);
(void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
//(void) fprintf(fp2, "P6\n%d %d\n255\n", dimx, dimy);
printf("header written\n");
    // Write RGB data
   // for (j=0; j < dimx; j++)
    //{
    for(i=0; i<50400; i++)
    {
    	UINT8 color[3];
	color[0]=convR[i];
	color[1]=convG[i];
	color[2]=convB[i];
	//color[0]=R1[k];
	//color[1]=G1[k];
	//color[2]=B1[k];
	k++;
	(void)fwrite(color,3,1,fp);
		//(void)fwrite(color,3,sizeof (color),fp2);
	//printf("\nError in writing convr %d\n",r1);
        //r2=fwrite(convG[i],1,sizeof(convG),fp);
	//printf("\nError in writing convr %d\n",r2);
        //r3=fwrite(convB[i],1,sizeof(convB),fp);
	//printf("\nError in writing convr %d\n",r3);
    }
    //}
    (void)fclose(fp);
}




int main()
{
    int i, j,fdout,fdin;
   
	fdin=IOread();
	
	
	colorquant();
	sharprof();
	IOwrite();
   

close(fdin);
    
 
}

